/*
 * LeafRegisterSerializer.h
 *
 *  Created on: Nov 2, 2012
 *      Author: m
 */

#ifndef LEAFREGISTERSERIALIZER_H_
#define LEAFREGISTERSERIALIZER_H_

#include <cstring>
#include "../../../physical_layer/physical_layer.h"
#include "BPlusTreeDefinitions.h"
#include "FrontCodingEncoder.h"

using physical::byte;
using physical::byteStream;
using physical::VariableStringSerializer;

#include <iostream>

class LeafRegisterSerializer: public physical::VariableSizeRecordSerializer< Leaf::registerType >
{
protected:
    VariableStringSerializer m_keySerializer;
    FrontCodingEncoder m_encoder;

public:
    LeafRegisterSerializer()
    {}

    ~LeafRegisterSerializer()
    {}

    void resetKey()
    {
        m_encoder.resetKey();
    }

    // Interfáz estática
    size_t serialize( const _T &element, byteStream block )
    {
        byte* blockPtr = block;
        size_t bytesUsed = 0;
        size_t totalBytesUsed = 0;
        DTRvalue_t value;
        FrontCodingEncoder::FrontCodedString encodedKey;

        // Codifico la key usando front-coding
        encodedKey = m_encoder.encode( element.getKey() );
        m_encoder.setKey( element.getKey() );

        // Serializo el header del encoding
        memcpy( blockPtr, &encodedKey.header, sizeof(FrontCodingEncoder::encoderHeader_t) );
        bytesUsed = sizeof(FrontCodingEncoder::encoderHeader_t);
        totalBytesUsed += bytesUsed;
        blockPtr += bytesUsed;

        // Serializo la key codificada
        bytesUsed = m_keySerializer.serialize( encodedKey.string, blockPtr );
        totalBytesUsed += bytesUsed;
        blockPtr += bytesUsed;

        // Serializo el value
        value = element.getValue();
        memcpy( blockPtr, &value, sizeof(DTRvalue_t) );
        bytesUsed = sizeof(DTRvalue_t);
        totalBytesUsed += bytesUsed;
        blockPtr += bytesUsed;

        return totalBytesUsed;
    }

    size_t deserialize( const byteStream block, _T &element )
    {
        byte* blockPtr = (byte*) block;
        size_t bytesUsed = 0;
        size_t totalBytesUsed = 0;
        DTRvalue_t value;
        FrontCodingEncoder::FrontCodedString encodedKey;
        std::string decodedKey;

        // Deserializo el encabezado del front-coding
        memcpy( &encodedKey.header, blockPtr, sizeof(FrontCodingEncoder::encoderHeader_t) );
        bytesUsed = sizeof(FrontCodingEncoder::encoderHeader_t);
        totalBytesUsed += bytesUsed;
        blockPtr += bytesUsed;

        // Deserializo la key
        bytesUsed = m_keySerializer.deserialize( blockPtr, encodedKey.string );
        totalBytesUsed += bytesUsed;
        blockPtr += bytesUsed;

        // Decodifico la key usando front-coding
        // ( tengo que meter un encoderResult y devolver un string )
        // encodedKey = m_encoder.decode( element.getKey(), encabezadoDelFrontCoding );
        decodedKey = m_encoder.decode( encodedKey );
        m_encoder.setKey( decodedKey );

        // Deserializo el value
        memcpy( &value, blockPtr, sizeof(DTRvalue_t) );
        bytesUsed = sizeof(DTRvalue_t);
        totalBytesUsed += bytesUsed;
        blockPtr += bytesUsed;

        // Puede ser esto:
        element = _T( decodedKey, value );

        // o esto:
        /*
        element.setKey( decodedKey );
        element.setValue( value );
        */

        return totalBytesUsed;
    }

    size_t computeSize( const _T &element )
    {
        size_t totalBytesUsed = 0;
        FrontCodingEncoder::FrontCodedString encodedKey;

        // Codifico la key usando front-coding
        encodedKey = m_encoder.encode( element.getKey() );
        m_encoder.setKey( element.getKey() );

        // Calculo tamaño del header del encoding
        totalBytesUsed += sizeof(FrontCodingEncoder::encoderHeader_t);

        // Calculo tamaño de la key codificada
        totalBytesUsed += m_keySerializer.computeSize( encodedKey.string );

        // calculo tamaño del value
        totalBytesUsed += sizeof(DTRvalue_t);

        return totalBytesUsed;
    }

    // Interfáz dinámica
    size_t serialize( const _T_ptr &elementPtr, byteStream block )
    {
        return this->serialize( *elementPtr, block );
    }

    size_t deserialize( const byteStream block, _T_ptr &elementPtr )
    {
        elementPtr.reset( new _T( std::string(), {} ) );
        return this->deserialize( block, *elementPtr );
    }

    size_t computeSize( const _T_ptr &elementPtr )
    {
        return this->computeSize( *elementPtr );
    }

};

#endif /* LEAFREGISTERSERIALIZER_H_ */
